/**
 * @ Author: luoqi
 * @ Create Time: 2024-07-12 09:27
 * @ Modified by: luoqi
 * @ Modified time: 2024-07-27 00:10
 * @ Description:
 */
#include <stdarg.h>
#include <stdbool.h>
#include "bsp.h"
#include "printf.h"

#ifdef BSP_UART_USING_DMA
#include "ringbuf.h"

static uint8_t uart3_rx_buf[256] = { 0 };
static int(*uart_recv_callback)(void *data, int len) = NULL;

static RingBufObj uart3_rx_ringbuf;
static uint8_t ringbuffer[512] = { 0 };
#endif

static int (*systick_callback)(void) = NULL;

extern void SystemClock_Config(void);

int bsp_init(void)
{
    // SCB->VTOR = 0x08010000;
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();
    MX_TIM1_Init();
    MX_USART3_UART_Init();

#ifdef BSP_UART_USING_DMA
    MX_DMA_Init();

    ringbuf_init(&uart3_rx_ringbuf, ringbuffer, sizeof(ringbuffer));

    HAL_UART_Receive_DMA(&huart3, uart3_rx_buf, sizeof(uart3_rx_buf));
    __HAL_UART_CLEAR_IDLEFLAG(&huart3);
    __HAL_UART_ENABLE_IT(&huart3, UART_IT_IDLE);

    HAL_Delay(200);
    ringbuf_clear(&uart3_rx_ringbuf);
#endif
    return 0;
}

int bsp_rtos_start(void)
{
    MX_ThreadX_Init();
    return 0;
}

int bsp_deinit()
{
    HAL_DeInit();
    return 0;
}

// void SysTick_Handler(void)
// {
//     HAL_IncTick();
//     if(systick_callback != NULL) {
//         systick_callback();
//     }
// }

#ifdef BSP_UART_USING_DMA
void USART3_IRQHandler(void)
{
    static bool isfirst = true;
    if(__HAL_UART_GET_FLAG(&huart3, UART_FLAG_IDLE) != RESET) {
        HAL_UART_AbortReceive(&huart3);
        __HAL_UART_CLEAR_IDLEFLAG(&huart3);
        uint16_t read_size = sizeof(uart3_rx_buf) - __HAL_DMA_GET_COUNTER(huart3.hdmarx);
        ringbuf_write_covern(&uart3_rx_ringbuf, uart3_rx_buf, read_size);
        if(!isfirst) {
            if(uart_recv_callback != NULL) {
                uart_recv_callback(uart3_rx_buf, read_size);
            }
        } else {
            isfirst = false;
        }
        HAL_UART_Receive_DMA(&huart3, uart3_rx_buf, sizeof(uart3_rx_buf));
    }

    HAL_UART_IRQHandler(&huart3);
}

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    if(huart->Instance == USART3) {
        HAL_UART_AbortReceive(&huart3);
        ringbuf_write_covern(&uart3_rx_ringbuf, uart3_rx_buf, sizeof(uart3_rx_buf));
        if(uart_recv_callback != NULL) {
            uart_recv_callback(uart3_rx_buf, sizeof(uart3_rx_buf));
        }
        HAL_UART_Receive_DMA(huart, uart3_rx_buf, sizeof(uart3_rx_buf));
    }
}

static volatile bool uart_send_cmplt = true;
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
    if(huart->Instance == USART3) {
        uart_send_cmplt = true;
    }
}

int bsp_uart_send(const uint8_t *data, uint32_t len)
{
    while(!uart_send_cmplt);
    uart_send_cmplt = false;
    return HAL_UART_Transmit_DMA(&huart3, data, len);
}

int bsp_uart_read(uint8_t *data, uint32_t len)
{
    return ringbuf_read(&uart3_rx_ringbuf, data, len);
}

void bsp_uart_recv_callback_set(int(*callback)(void *data, int len))
{
    uart_recv_callback = callback;
}
#endif

int bsp_uart_send_block(const uint8_t *data, uint32_t len, uint32_t timeout)
{
    int ret = HAL_UART_Transmit(&huart3, data, len, timeout);
    if(ret == HAL_OK){
        return len;
    } else {
        return ret;
    }
}

int bsp_printf(const char *fmt, ...)
{
    static char buf[128] = { 0 };
#ifdef BSP_UART_USING_DMA
    while(!uart_send_cmplt);
    uart_send_cmplt = false;
#endif
    va_list args;
    int sz = 0;
    va_start(args, fmt);
    sz = vsnprintf(buf, sizeof(buf) - 1, fmt, args);
    va_end(args);

    if(sz < 0) {
#ifdef BSP_UART_USING_DMA
        return HAL_UART_Transmit_DMA(&huart3, (uint8_t *)" #! Printf parse faild\r\n", 25);
#else
        return HAL_UART_Transmit(&huart3, (uint8_t *)" #! Printf parse faild\r\n", 25, 1000);
#endif
    }
#ifdef BSP_UART_USING_DMA
    return HAL_UART_Transmit_DMA(&huart3, (uint8_t *)buf, sz);
#else
    return HAL_UART_Transmit(&huart3, (uint8_t *)buf, sz, 1000);
#endif
}

int bsp_uart_read_block(uint8_t *data, uint32_t len, uint32_t timeout)
{
    int ret = HAL_UART_Receive(&huart3, data, len, timeout);
    if(ret == HAL_OK){
        return len;
    } else {
        return ret;
    }
}

void bsp_blink()
{
    HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_0);
    HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_3);
}

void bsp_mdelay(uint32_t ms)
{
    HAL_Delay(ms);
}

void bsp_systick_callback_set(int(*callback)(void))
{
    systick_callback = callback;
}

void bsp_reboot(void)
{
    __disable_irq();
    HAL_NVIC_SystemReset();
}

uint32_t bsp_strlen(const char *s)
{
    uint32_t len = 0;
    while(*s++ != '\0') {
        len++;
    }
    return len;
}

void *bsp_memcpy(void *dest, const void *src, uint32_t len)
{
    char *d;
    const char *s;
    if(((uint32_t)dest > ((uint32_t)src + len)) || (dest < src)) {
        d = dest;
        s = src;
        while(len--) {
            *d++ = *s++;
        }
    } else {
        d = (char *)((uint32_t)dest + len - 1);
        s = (char *)((uint32_t)src + len - 1);
        while(len--) {
            *d-- = *s--;
        }
    }
    return dest;
}
